package com.inspur.edp.formserver.vmmanager.increment;

import com.inspur.edp.cef.designtime.api.element.increment.GspCommonFieldIncrement;
import com.inspur.edp.cef.designtime.api.element.increment.ModifyFieldIncrement;
import com.inspur.edp.cef.designtime.api.entity.increment.CommonEntityIncrement;
import com.inspur.edp.cef.designtime.api.entity.increment.ModifyEntityIncrement;
import com.inspur.edp.cef.designtime.api.increment.IncrementType;
import com.inspur.edp.cef.designtime.api.increment.property.PropertyIncrement;
import com.inspur.edp.das.commonmodel.entity.GspCommonModel;
import com.inspur.edp.das.commonmodel.entity.increment.CommonModelIncrement;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.controlrule.rule.VoControlRule;
import com.inspur.edp.formserver.viewmodel.controlrule.rule.convert.VoControlRuleConvertor;
import com.inspur.edp.formserver.viewmodel.controlrule.ruledefine.VoControlRuleDef;
import com.inspur.edp.formserver.viewmodel.exception.ViewModelException;
import com.inspur.edp.formserver.viewmodel.increment.ViewModelIncrement;
import com.inspur.edp.formserver.viewmodel.increment.extract.ViewModelExtractor;
import com.inspur.edp.formserver.viewmodel.increment.merger.ViewModelMerger;
import com.inspur.edp.formserver.vmmanager.exception.VoManagerErrorCodes;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.metadata.rtcustomization.api.AbstractCustomizedContent;
import com.inspur.edp.metadata.rtcustomization.spi.CustomizationExtHandler;
import com.inspur.edp.metadata.rtcustomization.spi.args.ChangeMergeArgs;
import com.inspur.edp.metadata.rtcustomization.spi.args.Compare4SameLevelArgs;
import com.inspur.edp.metadata.rtcustomization.spi.args.ExtContentArgs;
import com.inspur.edp.metadata.rtcustomization.spi.args.MetadataMergeArgs;

import java.util.HashMap;
import java.util.Map;

public class ViewModelExtHandler implements CustomizationExtHandler {
    public static final String ContainEnumValues = "ContainEnumValues";

    @Override
    public AbstractCustomizedContent getExtContent(ExtContentArgs args) {
        GspMetadata oldMetadata = args.getBasicMetadata();
        GspMetadata newMetadata = args.getExtMetadata();
        if (oldMetadata == null)
            throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0029, null);
        if (newMetadata == null)
            throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0030, null);
        ViewModelExtractor extractor = new ViewModelExtractor();
        GspViewModel oldVo = (GspViewModel) oldMetadata.getContent();
        GspViewModel newVo = (GspViewModel) newMetadata.getContent();

        VoControlRuleDef def = new VoControlRuleDef();
        VoControlRule rule = new VoControlRule();
        VoControlRuleConvertor.convert2ControlRule(def, rule, oldVo);

        return extractor.extract(oldVo, newVo, rule, def);
    }

    @Override
    public GspMetadata merge(MetadataMergeArgs args) {

        GspMetadata extendMetadata = args.getExtendMetadata();
        AbstractCustomizedContent baseIncrement = args.getCustomizedContent();
        GspMetadata metadata = (GspMetadata) extendMetadata.clone();
        if (metadata == null)
            throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0031, null);
        ViewModelMerger merger = new ViewModelMerger(true);
//        GspViewModel extendVo = (GspViewModel)metadata.getContent();
        GspViewModel extendVo = ((GspViewModel) extendMetadata.getContent()).clone();

        VoControlRuleDef def = new VoControlRuleDef();
        VoControlRule rule = new VoControlRule();

        GspMetadata baseVoMetadata = args.getRootMetadata();

        VoControlRuleConvertor.convert2ControlRule(def, rule, (GspViewModel) baseVoMetadata.getContent());

        ViewModelIncrement extendIncrement = null;
//        ViewModelIncrement extendIncrement = (ViewModelIncrement)service.getChangeset(metadata.getHeader().getId() ,null, null);
        GspViewModel mergedVo = (GspViewModel) merger.merge(extendVo, (GspCommonModel) args.getRootMetadata().getContent(), extendIncrement == null ? new ViewModelIncrement() : extendIncrement, (ViewModelIncrement) baseIncrement, rule, def);
        metadata.setContent(mergedVo);

        return metadata;
    }

    @Override
    public AbstractCustomizedContent getExtContent4SameLevel(Compare4SameLevelArgs args) {
        GspMetadata oldMetadata = args.getOldMetadata();
        GspMetadata newMetadata = args.getMetadata();
        if (oldMetadata == null)
            throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0029, null);
        if (newMetadata == null)
            throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0030, null);

        ViewModelExtractor extractor = new ViewModelExtractor(!oldMetadata.isExtended());
        GspViewModel oldVo = (GspViewModel) oldMetadata.getContent();
        GspViewModel newVo = (GspViewModel) newMetadata.getContent();

        VoControlRuleDef def = new VoControlRuleDef();
        VoControlRule rule = new VoControlRule();
        VoControlRuleConvertor.convert2ControlRule(def, rule, oldVo);

        return extractor.extract(oldVo, newVo, rule, def);
    }

    //region changeMerge
    @Override
    public AbstractCustomizedContent changeMerge(ChangeMergeArgs changeMergeArgs) {
        CommonModelIncrement parentChange = (CommonModelIncrement) changeMergeArgs.getParentChage();
        CommonModelIncrement extendChange = (CommonModelIncrement) changeMergeArgs.getChangeToParent();

        if (extendChange == null)
            return parentChange;
        mergeChangeProperties(parentChange.getChangeProperties(), extendChange.getChangeProperties());

        if (extendChange.getMainEntityIncrement() != null && parentChange.getMainEntityIncrement() != null)
            mergeObjectIncrement(parentChange.getMainEntityIncrement(), extendChange.getMainEntityIncrement());

        return parentChange;
    }


    private void mergeObjectIncrement(ModifyEntityIncrement parentIncrement, ModifyEntityIncrement extendIncrement) {

        mergeChangeProperties(parentIncrement.getChangeProperties(), extendIncrement.getChangeProperties());

        for (Map.Entry<String, CommonEntityIncrement> childPair : parentIncrement.getChildEntitis().entrySet()) {
            if (childPair.getValue().getIncrementType() != IncrementType.Modify)
                continue;
            if (extendIncrement.getChildEntitis().containsKey(childPair.getKey())) {
                CommonEntityIncrement entityIncrement = extendIncrement.getChildEntitis().get(childPair.getKey());
                if (entityIncrement.getIncrementType() != IncrementType.Modify)
                    continue;
                mergeObjectIncrement((ModifyEntityIncrement) childPair.getValue(), (ModifyEntityIncrement) entityIncrement);
            }
        }

        for (Map.Entry<String, GspCommonFieldIncrement> elePair : parentIncrement.getFields().entrySet()) {
            GspCommonFieldIncrement fieldIncrement = elePair.getValue();
            if (fieldIncrement.getIncrementType() != IncrementType.Modify)
                continue;
            HashMap<String, GspCommonFieldIncrement> extendFields = extendIncrement.getFields();
            if (extendFields.containsKey(elePair.getKey())) {
                GspCommonFieldIncrement gspCommonFieldIncrement = extendFields.get(elePair.getKey());
                if (gspCommonFieldIncrement.getIncrementType() != IncrementType.Modify)
                    continue;
                mergeElementIncrement((ModifyFieldIncrement) fieldIncrement, (ModifyFieldIncrement) gspCommonFieldIncrement);
            }
        }

    }

    private void mergeElementIncrement(ModifyFieldIncrement parentIncrement, ModifyFieldIncrement extendIncrement) {
        mergeChangeProperties(parentIncrement.getChangeProperties(), extendIncrement.getChangeProperties());
    }

    private void mergeChangeProperties(HashMap<String, PropertyIncrement> parentChanges, HashMap<String, PropertyIncrement> extendChanges) {
        for (Map.Entry<String, PropertyIncrement> changePair : extendChanges.entrySet()) {
            if (parentChanges.containsKey(changePair.getKey())) {
                // TODO: 2023/8/21 由于枚举之前抽取增量，增量合并时，会将新的增量和已经存在的增量合并，会将新的变更移除，此处暂不处理枚举的增量
                if (ContainEnumValues.equals(changePair.getKey()))
                    continue;
                parentChanges.remove(changePair.getKey());
            }
        }
    }

    //endregion

}
